package com.lolaage.tracks.adapter;

import java.util.Vector;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;

import com.lolaage.tracks.MyLocationPolicy;
import com.lolaage.tracks.MyLocationPrivider;
import com.lolaage.tracks.MyLocationValider;
import com.lolaage.tracks.util.CycledThread;
import com.lolaage.tracks.util.CycledThread.OnTimeoutListener;


/*********************************************************
 * @author : zhaohua
 * @version : 2012-9-19
 * @see : 自定位位置提供者
 * @Copyright : copyrights reserved by personal 2007-2011
 **********************************************************/
public class MyLocationManager implements MyLocationPrivider
{
    private static final String TAG = "MyLocationManager";
    private Vector<OnLocationListener> mLocListeners = new Vector<OnLocationListener>();
    private LocationManager myTracksLocationManager;
    private MyLocationPolicy mLocationListenerPolicy;
    private MyLocationValider mLocationValider;
    /** 当前最好一个有效的位置 */
    private Location currentBestLocation;
    private CycledThread mLocKeepThread;
    private CycledThread mLocTask;
    private Handler mHandler = new Handler();
    boolean isLocating = false;
    
    private static MyLocationManager instance;
    public static MyLocationManager getInstace(Context context)
    {
        if (instance == null)
        {
            instance = new MyLocationManager(context);
        }
        return instance;
    }
    private MyLocationManager(Context context)
    {
        myTracksLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        
        mLocationListenerPolicy = new AdaptiveLocationPolicy(10000, 300000, 10, 50);
        mLocationValider = new TrackLocationValider();
    }
    
    @Override
    public void addLocationListener(OnLocationListener listener)
    {
        if(listener != null && !mLocListeners.contains(listener))
        {
            mLocListeners.add(listener);
        }
    }

    @Override
    public void rmvLocationListener(OnLocationListener listener)
    {
        if(listener != null && mLocListeners.contains(listener))
        {
            mLocListeners.remove(listener);
        }
    }

    @Override
    public void startKeepLocation(int intalTime)
    {
        if(mLocKeepThread == null)
        {
            mLocKeepThread = new CycledThread(new Runnable()
            {
                @Override
                public void run()
                {
                    Log.d(TAG, "-->startKeepLocation start ...");
                    mHandler.post(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            startLocation(true, 0);
                        }
                    });
                }
            }, intalTime);
        }
        if(!mLocKeepThread.isAlive())
        {
            mLocKeepThread.start();
        }
    }

    @Override
    public void stopKeepLocation()
    {
        if(mLocKeepThread != null)
        {
            mLocKeepThread._stop();
            mLocKeepThread = null;
        }
        unregisterLocationListener();
    }

    @Override
    public void setLocationOption(int minTime, int minDist)
    {
        mLocationListenerPolicy.updateIdleTime(minTime,minDist);
    }

    @Override
    public void setPrivity(int locMode)
    {
        // do nothing ...
    }
    
    @Override
    public void setLocationPolicy(MyLocationPolicy policy)
    {
        mLocationListenerPolicy = policy;
    }
    
    @Override
    public void setLocationValider(MyLocationValider valider)
    {
        mLocationValider = valider;
    }
    
    @Override
    public void startLocation(boolean update,int timeout)
    {
        // 定位检核
        if(currentBestLocation != null && !update)
        {
            Location lastLoc = myTracksLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            if(mLocationValider.isBetterLocation(currentBestLocation,lastLoc))
            {
                currentBestLocation = lastLoc;
                mHandler.postDelayed(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        // 获取缓存最新
                        onLocOK();
                    }
                },3000);
                return;
            }
        }
        if(isLocating())
        {
            // 正在定位
            return;
        }
        try{
            registerLocationListener();
            if(timeout > 3000)
            {
                mLocTask = new CycledThread(200, timeout, new OnTimeoutListener()
                {
                    @Override
                    public void onTimeout() 
                    {
                        mHandler.post(new Runnable()
                        {
                            @Override
                            public void run()
                            {
                                mLocTask = null;
                                unregisterLocationListener();
                                onLocErr();
                            }
                        });
                    }
                });
                mLocTask.start();
            }
        } catch (Exception e) 
        {
            Log.w(TAG, e);
            //重复启动容错
        }
    }

    @Override
    public boolean isLocating()
    {
        return mLocTask != null && mLocTask.isAlive();
    }
    
    public void destory() 
    {
        unregisterLocationListener();
    }
    
    private void registerLocationListener()
    {
        unregisterLocationListener();

        if (myTracksLocationManager == null)
        {
            Log.e(TAG, "locationManager is null.");
            return;
        }
        try
        {
            long interval = mLocationListenerPolicy.getDesiredPollingInterval();
            int  interDist = mLocationListenerPolicy.getDesiredPollingDistance();
            myTracksLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval, interDist, mLocListener);
            isLocating = true;
            Log.d(TAG, "---> registerLocationListener interval = " + interval + "; dist = " + interDist);
        } catch (RuntimeException e)
        {
            Log.e(TAG, "Could not register location listener.", e);
        }
    }

    /**
     * Unregisters the location manager.
     */
    private void unregisterLocationListener()
    {
        if (myTracksLocationManager == null)
        {
            Log.e(TAG, "locationManager is null.");
            return;
        }
        myTracksLocationManager.removeUpdates(mLocListener);
        isLocating = false;
        Log.d(TAG, "---> unregisterLocationListener ");
    }
    
    private void onLocOK()
    {
        Log.d(TAG, "-->get location:" + currentBestLocation.getLongitude() + "," + currentBestLocation.getLatitude());
        for(OnLocationListener listener : mLocListeners)
        {
            listener.onLocationChanged(currentBestLocation);
        }
    }

    private void onLocErr()
    {
        Log.d(TAG, "-->get location timeout ");
        Location lastLoc = myTracksLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        if (lastLoc != null && mLocationValider.isBetterLocation(currentBestLocation,lastLoc))
        {
            currentBestLocation = lastLoc;
            onLocOK();
        } else
        {
            for (OnLocationListener listener : mLocListeners)
            {
                listener.onLocationError();
            }
        }
    }
    
    private LocationListener mLocListener = new LocationListener()
    {
        @Override
        public void onLocationChanged(Location location)
        {
            Log.d(TAG, "--> onLocationChanged reached!" + location);
            if (mLocationValider.isBetterLocation(currentBestLocation,location))
            {
                if (mLocTask != null)
                {
                    mLocTask._stop();
                    mLocTask = null;
                }
                currentBestLocation = location;
                onLocOK();
            }
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras)
        {
            
        }

        @Override
        public void onProviderEnabled(String provider)
        {
            
        }

        @Override
        public void onProviderDisabled(String provider)
        {
            
        }
    };
}
